package com.ferry.transport.api.config;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by daiyong
 */
public class ChildConfig implements TcpConfig {

	private volatile int ioRatio = 99;
	private volatile int rcvBuf = -1;
	private volatile int sndBuf = -1;
	private volatile int linger = -1;
	private volatile int ipTos = -1;
	private volatile int connectTimeoutMillis = -1;
	private volatile int writeBufferHighWaterMark = -1;
	private volatile int writeBufferLowWaterMark = -1;
	private volatile boolean reuseAddress = true;
	private volatile boolean keepAlive = true;
	private volatile boolean tcpNoDelay = true;
	private volatile boolean allowHalfClosure = false;
	private volatile long tcpNotSentLowAt = -1;
	private volatile int tcpKeepCnt = -1;
	private volatile int tcpUserTimeout = -1;
	private volatile int tcpKeepIdle = -1;
	private volatile int tcpKeepInterval = -1;
	private volatile boolean edgeTriggered = true;
	private volatile boolean tcpCork = false;
	private volatile boolean tcpQuickAck = true;
	private volatile boolean ipTransparent = false;
	private volatile boolean tcpFastOpenConnect = false;

	@Override
	public List<TcpOption<?>> getOptions() {
		List<TcpOption<?>> options = new ArrayList<>();
		options.add(TcpOption.IO_RATIO);
		options.add(TcpOption.SO_RCVBUF);
		options.add(TcpOption.SO_SNDBUF);
		options.add(TcpOption.SO_LINGER);
		options.add(TcpOption.SO_REUSEADDR);
		options.add(TcpOption.CONNECT_TIMEOUT_MILLIS);
		options.add(TcpOption.WRITE_BUFFER_HIGH_WATER_MARK);
		options.add(TcpOption.WRITE_BUFFER_LOW_WATER_MARK);
		options.add(TcpOption.KEEP_ALIVE);
		options.add(TcpOption.TCP_NODELAY);
		options.add(TcpOption.IP_TOS);
		options.add(TcpOption.ALLOW_HALF_CLOSURE);
		options.add(TcpOption.TCP_NOTSENT_LOWAT);
		options.add(TcpOption.TCP_KEEPCNT);
		options.add(TcpOption.TCP_USER_TIMEOUT);
		options.add(TcpOption.TCP_KEEPIDLE);
		options.add(TcpOption.TCP_KEEPINTVL);
		options.add(TcpOption.EDGE_TRIGGERED);
		options.add(TcpOption.TCP_CORK);
		options.add(TcpOption.TCP_QUICKACK);
		options.add(TcpOption.IP_TRANSPARENT);
		options.add(TcpOption.TCP_FASTOPEN_CONNECT);

		return options;
	}

	@Override
	public <T> T getOption(TcpOption<?> option) {

		if (option == TcpOption.IO_RATIO) {
			return (T) Integer.valueOf(getIoRatio());
		}
		if (option == TcpOption.SO_RCVBUF) {
			return (T) Integer.valueOf(getRcvBuf());
		}
		if (option == TcpOption.SO_SNDBUF) {
			return (T) Integer.valueOf(getSndBuf());
		}
		if (option == TcpOption.SO_LINGER) {
			return (T) Integer.valueOf(getLinger());
		}
		if (option == TcpOption.IP_TOS) {
			return (T) Integer.valueOf(getIpTos());
		}
		if (option == TcpOption.CONNECT_TIMEOUT_MILLIS) {
			return (T) Integer.valueOf(getConnectTimeoutMillis());
		}
		if (option == TcpOption.WRITE_BUFFER_HIGH_WATER_MARK) {
			return (T) Integer.valueOf(getWriteBufferHighWaterMark());
		}
		if (option == TcpOption.WRITE_BUFFER_LOW_WATER_MARK) {
			return (T) Integer.valueOf(getWriteBufferLowWaterMark());
		}
		if (option == TcpOption.SO_REUSEADDR) {
			return (T) Boolean.valueOf(isReuseAddress());
		}
		if (option == TcpOption.KEEP_ALIVE) {
			return (T) Boolean.valueOf(isKeepAlive());
		}
		if (option == TcpOption.TCP_NODELAY) {
			return (T) Boolean.valueOf(isTcpNoDelay());
		}
		if (option == TcpOption.ALLOW_HALF_CLOSURE) {
			return (T) Boolean.valueOf(isAllowHalfClosure());
		}
		if (option == TcpOption.TCP_NOTSENT_LOWAT) {
			return (T) Long.valueOf(getTcpNotSentLowAt());
		}
		if (option == TcpOption.TCP_KEEPIDLE) {
			return (T) Integer.valueOf(getTcpKeepIdle());
		}
		if (option == TcpOption.TCP_KEEPINTVL) {
			return (T) Integer.valueOf(getTcpKeepInterval());
		}
		if (option == TcpOption.TCP_KEEPCNT) {
			return (T) Integer.valueOf(getTcpKeepCnt());
		}
		if (option == TcpOption.TCP_USER_TIMEOUT) {
			return (T) Integer.valueOf(getTcpUserTimeout());
		}
		if (option == TcpOption.EDGE_TRIGGERED) {
			return (T) Boolean.valueOf(isEdgeTriggered());
		}
		if (option == TcpOption.TCP_CORK) {
			return (T) Boolean.valueOf(isTcpCork());
		}
		if (option == TcpOption.TCP_QUICKACK) {
			return (T) Boolean.valueOf(isTcpQuickAck());
		}
		if (option == TcpOption.IP_TRANSPARENT) {
			return (T) Boolean.valueOf(isIpTransparent());
		}
		if (option == TcpOption.TCP_FASTOPEN_CONNECT) {
			return (T) Boolean.valueOf(isTcpFastOpenConnect());
		}

		return null;
	}

	@Override
	public <T> boolean setOption(TcpOption<?> option, T value) {

		if (option == TcpOption.IO_RATIO) {
			setIoRatio(castToInteger(value));
		} else if (option == TcpOption.SO_RCVBUF) {
			setRcvBuf(castToInteger(value));
		} else if (option == TcpOption.SO_SNDBUF) {
			setSndBuf(castToInteger(value));
		} else if (option == TcpOption.SO_LINGER) {
			setLinger(castToInteger(value));
		} else if (option == TcpOption.IP_TOS) {
			setIpTos(castToInteger(value));
		} else if (option == TcpOption.CONNECT_TIMEOUT_MILLIS) {
			setConnectTimeoutMillis(castToInteger(value));
		} else if (option == TcpOption.WRITE_BUFFER_HIGH_WATER_MARK) {
			setWriteBufferHighWaterMark(castToInteger(value));
		} else if (option == TcpOption.WRITE_BUFFER_LOW_WATER_MARK) {
			setWriteBufferLowWaterMark(castToInteger(value));
		} else if (option == TcpOption.SO_REUSEADDR) {
			setReuseAddress(castToBoolean(value));
		} else if (option == TcpOption.KEEP_ALIVE) {
			setKeepAlive(castToBoolean(value));
		} else if (option == TcpOption.TCP_NODELAY) {
			setTcpNoDelay(castToBoolean(value));
		} else if (option == TcpOption.ALLOW_HALF_CLOSURE) {
			setAllowHalfClosure(castToBoolean(value));
		} else if (option == TcpOption.TCP_NOTSENT_LOWAT) {
			setTcpNotSentLowAt(castToLong(value));
		} else if (option == TcpOption.TCP_KEEPIDLE) {
			setTcpKeepIdle(castToInteger(value));
		} else if (option == TcpOption.TCP_KEEPCNT) {
			setTcpKeepCnt(castToInteger(value));
		} else if (option == TcpOption.TCP_KEEPINTVL) {
			setTcpKeepInterval(castToInteger(value));
		} else if (option == TcpOption.TCP_USER_TIMEOUT) {
			setTcpUserTimeout(castToInteger(value));
		} else if (option == TcpOption.IP_TRANSPARENT) {
			setIpTransparent(castToBoolean(value));
		} else if (option == TcpOption.EDGE_TRIGGERED) {
			setEdgeTriggered(castToBoolean(value));
		} else if (option == TcpOption.TCP_CORK) {
			setTcpCork(castToBoolean(value));
		} else if (option == TcpOption.TCP_QUICKACK) {
			setTcpQuickAck(castToBoolean(value));
		} else if (option == TcpOption.TCP_FASTOPEN_CONNECT) {
			setTcpFastOpenConnect(castToBoolean(value));
		}

		return true;

	}

	private static Integer castToInteger(Object value) {
		if (value instanceof Integer) {
			return (Integer) value;
		}

		if (value instanceof String) {
			return Integer.valueOf((String) value);
		}

		throw new IllegalArgumentException(value.getClass().toString());
	}

	private static Long castToLong(Object value) {
		if (value instanceof Long) {
			return (Long) value;
		}

		if (value instanceof String) {
			return Long.valueOf((String) value);
		}

		throw new IllegalArgumentException(value.getClass().toString());
	}

	private static Boolean castToBoolean(Object value) {
		if (value instanceof Boolean) {
			return (Boolean) value;
		}

		if (value instanceof String) {
			return Boolean.valueOf((String) value);
		}

		throw new IllegalArgumentException(value.getClass().toString());
	}

	public int getIoRatio() {
		return ioRatio;
	}

	public void setIoRatio(int ioRatio) {
		this.ioRatio = ioRatio;
	}

	public int getRcvBuf() {
		return rcvBuf;
	}

	public void setRcvBuf(int rcvBuf) {
		this.rcvBuf = rcvBuf;
	}

	public int getSndBuf() {
		return sndBuf;
	}

	public void setSndBuf(int sndBuf) {
		this.sndBuf = sndBuf;
	}

	public int getLinger() {
		return linger;
	}

	public void setLinger(int linger) {
		this.linger = linger;
	}

	public int getIpTos() {
		return ipTos;
	}

	public void setIpTos(int ipTos) {
		this.ipTos = ipTos;
	}

	public int getConnectTimeoutMillis() {
		return connectTimeoutMillis;
	}

	public void setConnectTimeoutMillis(int connectTimeoutMillis) {
		this.connectTimeoutMillis = connectTimeoutMillis;
	}

	public int getWriteBufferHighWaterMark() {
		return writeBufferHighWaterMark;
	}

	public void setWriteBufferHighWaterMark(int writeBufferHighWaterMark) {
		this.writeBufferHighWaterMark = writeBufferHighWaterMark;
	}

	public int getWriteBufferLowWaterMark() {
		return writeBufferLowWaterMark;
	}

	public void setWriteBufferLowWaterMark(int writeBufferLowWaterMark) {
		this.writeBufferLowWaterMark = writeBufferLowWaterMark;
	}

	public boolean isReuseAddress() {
		return reuseAddress;
	}

	public void setReuseAddress(boolean reuseAddress) {
		this.reuseAddress = reuseAddress;
	}

	public boolean isKeepAlive() {
		return keepAlive;
	}

	public void setKeepAlive(boolean keepAlive) {
		this.keepAlive = keepAlive;
	}

	public boolean isTcpNoDelay() {
		return tcpNoDelay;
	}

	public void setTcpNoDelay(boolean tcpNoDelay) {
		this.tcpNoDelay = tcpNoDelay;
	}

	public boolean isAllowHalfClosure() {
		return allowHalfClosure;
	}

	public void setAllowHalfClosure(boolean allowHalfClosure) {
		this.allowHalfClosure = allowHalfClosure;
	}

	public long getTcpNotSentLowAt() {
		return tcpNotSentLowAt;
	}

	public void setTcpNotSentLowAt(long tcpNotSentLowAt) {
		this.tcpNotSentLowAt = tcpNotSentLowAt;
	}

	public int getTcpKeepCnt() {
		return tcpKeepCnt;
	}

	public void setTcpKeepCnt(int tcpKeepCnt) {
		this.tcpKeepCnt = tcpKeepCnt;
	}

	public int getTcpUserTimeout() {
		return tcpUserTimeout;
	}

	public void setTcpUserTimeout(int tcpUserTimeout) {
		this.tcpUserTimeout = tcpUserTimeout;
	}

	public int getTcpKeepIdle() {
		return tcpKeepIdle;
	}

	public void setTcpKeepIdle(int tcpKeepIdle) {
		this.tcpKeepIdle = tcpKeepIdle;
	}

	public int getTcpKeepInterval() {
		return tcpKeepInterval;
	}

	public void setTcpKeepInterval(int tcpKeepInterval) {
		this.tcpKeepInterval = tcpKeepInterval;
	}

	public boolean isEdgeTriggered() {
		return edgeTriggered;
	}

	public void setEdgeTriggered(boolean edgeTriggered) {
		this.edgeTriggered = edgeTriggered;
	}

	public boolean isTcpCork() {
		return tcpCork;
	}

	public void setTcpCork(boolean tcpCork) {
		this.tcpCork = tcpCork;
	}

	public boolean isTcpQuickAck() {
		return tcpQuickAck;
	}

	public void setTcpQuickAck(boolean tcpQuickAck) {
		this.tcpQuickAck = tcpQuickAck;
	}

	public boolean isIpTransparent() {
		return ipTransparent;
	}

	public void setIpTransparent(boolean ipTransparent) {
		this.ipTransparent = ipTransparent;
	}

	public boolean isTcpFastOpenConnect() {
		return tcpFastOpenConnect;
	}

	public void setTcpFastOpenConnect(boolean tcpFastOpenConnect) {
		this.tcpFastOpenConnect = tcpFastOpenConnect;
	}
}
